package cn.xx.service.impl;

import cn.xx.dao.UserDOMapper;
import cn.xx.dao.UserPasswordDOMapper;
import cn.xx.dataobject.UserDO;
import cn.xx.dataobject.UserPasswordDO;
import cn.xx.error.BusinessException;
import cn.xx.error.EmBusinessError;
import cn.xx.service.UserService;
import cn.xx.service.model.UserModel;
import cn.xx.validator.ValidationResult;
import cn.xx.validator.ValidatorImpl;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.concurrent.TimeUnit;

/**
 * @author xiexu
 * @create 2022-04-19 21:08
 */
@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserDOMapper userDOMapper;

    @Autowired
    private UserPasswordDOMapper userPasswordDOMapper;

    @Autowired
    private ValidatorImpl validator;

    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    public UserModel getUserById(Integer id) {
        // 调用UserDOMapper获取到对应的用户dataobject
        UserDO userDO = userDOMapper.selectByPrimaryKey(id);
        if (userDO == null) {
            return null;
        }
        // 通过用户id获取对应的用户加密密码信息
        UserPasswordDO userPasswordDO = userPasswordDOMapper.selectByUserId(userDO.getId());
        return convertFromDataObject(userDO, userPasswordDO);
    }

    // 从缓存中获取用户信息
    public UserModel getUserByIdInCache(Integer id) {
        // 根据用户id去redis缓存中获取用户信息
        UserModel userModel = (UserModel) redisTemplate.opsForValue().get("user_validate_" + id);
        // 如果用户信息为空，就去数据库中查询用户信息，并将用户信息存储中redis缓存中，并设置过期时间10分钟
        if (userModel == null) {
            userModel = this.getUserById(id);
            redisTemplate.opsForValue().set("user_validate_" + id, userModel);
            redisTemplate.expire("user_validate_" + id, 10, TimeUnit.MINUTES);
        }
        return userModel;
    }

    // 封装userDO的属性和userPasswordDO的属性到UserModel对象
    private UserModel convertFromDataObject(UserDO userDO, UserPasswordDO userPasswordDO) {
        if (userDO == null) {
            return null;
        }
        // 创建UserModel对象
        UserModel userModel = new UserModel();
        // 把对应userDO的属性拷贝到userModel里面
        BeanUtils.copyProperties(userDO, userModel);
        if (userPasswordDO != null) {
            // 将获取到的密码封装到userModel里面
            userModel.setEncrptPassword(userPasswordDO.getEncrptPassword());
        }
        // 返回userModel
        return userModel;
    }

    @Override
    @Transactional //声明事务
    public void register(UserModel userModel) throws BusinessException {
        if (userModel == null) {
            throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR);
        }
        // 校验当前userModel的各个属性是否符合要求
        ValidationResult result = validator.validate(userModel);
        if (result.isHasErrors()) { // 若存在错误，则抛出异常
            throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR, result.getErrMsg());
        }

        // 实现UserModel转成UserDO的方法（model -> dataobject）
        UserDO userDO = convertFromModel(userModel);
        try {
            // insertSelective相对于insert方法，不会覆盖掉数据库的默认值
            userDOMapper.insertSelective(userDO);
        } catch (DuplicateKeyException ex) { //如果手机号重复就会抛出这个异常
            throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR, "该手机号已被注册");
        }

        // 然后将userDO生成的自增id设置到userModel里面
        userModel.setId(userDO.getId()); // 到这个地方userDO就已经有了从UserDOMapper.xml传过来的自增id了
        // 实现UserModel转成userPasswordDO的方法（model -> dataobject）
        UserPasswordDO userPasswordDO = convertPasswordFromModel(userModel);
        // insertSelective相对于insert方法，不会覆盖掉数据库的默认值
        userPasswordDOMapper.insertSelective(userPasswordDO);
        return;
    }

    // 封装userModel的属性到UserDO对象
    private UserDO convertFromModel(UserModel userModel) {
        if (userModel == null) {
            return null;
        }
        // 创建userDO对象
        UserDO userDO = new UserDO();
        // 把对应userModel的属性拷贝到userDO里面
        BeanUtils.copyProperties(userModel, userDO);
        return userDO;
    }

    // 封装userModel的属性到UserPasswordDO对象
    private UserPasswordDO convertPasswordFromModel(UserModel userModel) {
        if (userModel == null) {
            return null;
        }
        // 创建userPasswordDO对象
        UserPasswordDO userPasswordDO = new UserPasswordDO();
        // 封装userModel对象的密码和id到userPasswordDO对象
        userPasswordDO.setEncrptPassword(userModel.getEncrptPassword()); // 加密后的密码
        userPasswordDO.setUserId(userModel.getId());
        return userPasswordDO;
    }

    @Override
    public UserModel validateLogin(String telphone, String encrptPassword) throws BusinessException {
        // 通过用户手机获取用户信息
        UserDO userDO = userDOMapper.selectByTelphone(telphone);
        if (userDO == null) {
            throw new BusinessException(EmBusinessError.USER_LOOGIN_FAIL);
        }
        // 然后通过userDO的用户id到密码表中查询对应的加密后的密码
        UserPasswordDO userPasswordDO = userPasswordDOMapper.selectByUserId(userDO.getId());
        // 将用户信息和对应加密后的密码一起封装成UserModel
        UserModel userModel = convertFromDataObject(userDO, userPasswordDO);
        // 比对用户信息内加密的密码是否和传输进来的密码相匹配
        if (!StringUtils.equals(encrptPassword, userModel.getEncrptPassword())) {
            throw new BusinessException(EmBusinessError.USER_LOOGIN_FAIL);
        }
        return userModel;
    }

}
